package org.wu.spring.db.integration.compare.infrastructure.persistence.clickhouse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.wu.framework.lazy.database.datasource.proxy.LazyWideDataSource;
import org.wu.framework.lazy.database.datasource.proxy.builder.LazyWideDataSourceBuild;
import org.wu.framework.lazy.orm.core.config.DefaultLazyOperationAttribute;
import org.wu.framework.lazy.orm.core.config.enums.LazyDataSourceType;
import org.wu.framework.lazy.orm.core.config.prop.DefaultLazyDataSourceAttribute;
import org.wu.framework.lazy.orm.core.config.prop.LazyDataSourceAttribute;
import org.wu.framework.lazy.orm.core.persistence.conf.LazyColumn;
import org.wu.framework.lazy.orm.core.persistence.conf.LazyTableEndpoint;
import org.wu.framework.lazy.orm.core.source.adapter.SourceFactory;
import org.wu.framework.lazy.orm.database.lambda.domain.LazyPage;
import org.wu.framework.lazy.orm.database.lambda.dynamic.function.DynamicDatasourceSupport;
import org.wu.framework.lazy.orm.database.lambda.stream.lambda.LazyLambdaStream;
import org.wu.framework.lazy.orm.database.sql.expand.database.persistence.factory.LazyLambdaStreamFactory;
import org.wu.framework.web.response.Result;
import org.wu.framework.web.response.ResultFactory;
import org.wu.spring.db.integration.compare.config.DbConfig;
import org.wu.spring.db.integration.compare.domain.model.sys.user.DbComparisonRepository;
import org.wu.spring.db.integration.compare.domain.model.sys.user.SysUser;
import org.wu.spring.db.integration.compare.enums.DatabaseType;
import org.wu.spring.db.integration.compare.enums.ExecuteType;
import org.wu.spring.db.integration.compare.infrastructure.persistence.DbComparisonRepositoryAbstract;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;


@Component
public class LazyClickhouseComparisonRepository extends DbComparisonRepositoryAbstract implements DbComparisonRepository {


    private static final Logger log = LoggerFactory.getLogger(LazyClickhouseComparisonRepository.class);
    private final DbConfig dbConfig;
    private final LazyLambdaStream lazyLambdaStream;

    private final String DATABASE_ID = "ck";
    public LazyClickhouseComparisonRepository(DbConfig dbConfig) {
        this.dbConfig = dbConfig;
        DbConfig.ClickHouseConfig clickHouseConfig = dbConfig.getClickHouseConfig();
        String url = clickHouseConfig.getUrl();
        String username = clickHouseConfig.getUsername();
        String password = clickHouseConfig.getPassword();

        DefaultLazyOperationAttribute defaultLazyOperationAttribute = new DefaultLazyOperationAttribute();
        defaultLazyOperationAttribute.setPrintfQuery(false);

        LazyWideDataSourceBuild lazyWideDataSourceBuild = new LazyWideDataSourceBuild();
        lazyWideDataSourceBuild
                .url(url)
                .driverName("com.mysql.cj.jdbc.Driver")
                .username(username)
                .password(password);
        LazyWideDataSource build = lazyWideDataSourceBuild.build();


        this.lazyLambdaStream = LazyLambdaStreamFactory.
                createLazyLambdaStream(DATABASE_ID, build,defaultLazyOperationAttribute);
    }

    /**
     * describe 批量新增
     *
     * @param rowSize    @return {@link Result <  List  < SysUser >>} 新增后领域对象集合
     * @param columnSize
     * @author Jia wei Wu
     * @date 2024/02/28 11:27 上午
     **/
    @Override
    protected Result<List<SysUser>> doBatchStory(int rowSize, int columnSize) throws Exception {
        String schemaName = dbConfig.getSchemaName();
        String tableName = dbConfig.getTableName();

        AtomicReference<LocalDateTime> startTime = new AtomicReference<>(LocalDateTime.now());
        AtomicBoolean success = new AtomicBoolean(true);

        DynamicDatasourceSupport.doOtherSilently(LazyDataSourceType.CLICK_HOUSE, DATABASE_ID, schemaName, () -> {

        // 创建数据库
        lazyLambdaStream.executeSQLForBean("create database if not exists {0};", Boolean.class, schemaName);
        // 删除表
//        lazyLambdaStream.executeSQLForBean("drop table if exists {0}.{1}", Integer.class, schemaName, tableName);

        lazyLambdaStream.executeSQLForBean(" CREATE TABLE IF NOT EXISTS   {0}.{1}\n" +
                "(\n" +
                "\n" +
                "    `time` DateTime\n" +
                ")\n" +
                "ENGINE = ReplacingMergeTree\n" +
                "PARTITION BY toYYYYMMDD(toDateTime(time))\n" +
                "PRIMARY KEY time\n" +
                "ORDER BY time\n" +
                "SETTINGS index_granularity = 8192; ", Integer.class, schemaName, tableName);

        // 创建表
        Map<String, Object> rowData = getRowData(columnSize);
            Map<String, Object> newRowData =
                    rowData.entrySet().stream()
                            .filter(stringObjectEntry -> !stringObjectEntry.getKey().equals("time"))
                            .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
            LazyTableEndpoint<?> lazyTableEndpoint = SourceFactory
                    .analyzeLazyTableFromMap(LazyDataSourceType.CLICK_HOUSE, schemaName, tableName, newRowData);


            lazyLambdaStream.updateTable(lazyTableEndpoint);


            startTime.set(LocalDateTime.now());
            try {
                List<Map<String, Object>> weakInsertList=new ArrayList<>();
                for (int i = 0; i < rowSize; i++) {
                    rowData = getRowData(columnSize,i);
                    weakInsertList.add(rowData);
                }
                int groupSize=(columnSize*rowSize)/10000;
                lazyLambdaStream.weakInsertMultiple(schemaName, tableName, weakInsertList,1000);
            } catch (Exception e) {
                e.printStackTrace();
                success.set(false);
            }

        });
        LocalDateTime endTime = LocalDateTime.now();
        storyRecord(DatabaseType.CLICKHOUSE, ExecuteType.batchStory, startTime.get(), endTime, rowSize,columnSize , success.get());


        return ResultFactory.successOf();
    }

    /**
     * describe 分页查询多个
     *
     * @param rowSize    当前页数
     * @param columnSize
     * @return {@link Result<   LazyPage   <SysUser>>} 分页领域对象
     * @author Jia wei Wu
     * @date 2024/02/28 11:27 上午
     **/
    @Override
    protected Result<LazyPage<SysUser>> doFindPage(int rowSize, int columnSize) throws Exception {
        String schemaName = dbConfig.getSchemaName();
        String tableName = dbConfig.getTableName();
        if(rowSize>1){
            return ResultFactory.successOf();
        }


        AtomicBoolean success = new AtomicBoolean(true);
        AtomicReference<LocalDateTime> startTime = new AtomicReference<>(LocalDateTime.now());

        DynamicDatasourceSupport.doOtherSilently(LazyDataSourceType.CLICK_HOUSE, DATABASE_ID, schemaName, () -> {
            // 查询表字段
            String tableColumnListSql = SourceFactory.findTableColumnListSql(LazyDataSourceType.CLICK_HOUSE, schemaName, tableName);
            Class<? extends LazyColumn> columnInfoClass = SourceFactory.findColumnInfoClass(LazyDataSourceType.CLICK_HOUSE);
            List<? extends LazyColumn> lazyColumns = lazyLambdaStream.executeSQL(tableColumnListSql, columnInfoClass);
            String queryColumn = lazyColumns.subList(0, (Math.min(columnSize, lazyColumns.size()))).stream().map(LazyColumn::getColumnName).collect(Collectors.joining(","));


            success.set(true);
            startTime.set(LocalDateTime.now());
            try {
                // 过滤指定条数
                List<HashMap> objects = lazyLambdaStream.executeSQL("select {0} from {1}.{2} limit {3}", HashMap.class,
                        queryColumn,
                        schemaName,
                        tableName,
                        rowSize
                );
                log.info("find success rowSize {},columnSize:{}",objects.size(),objects.get(0).size());
            } catch (Exception e) {
                e.printStackTrace();
                success.set(false);
            }
        });

        LocalDateTime endTime = LocalDateTime.now();
        storyRecord(DatabaseType.CLICKHOUSE, ExecuteType.findPage, startTime.get(), endTime,rowSize,columnSize , success.get());


        return ResultFactory.successOf();
    }
}
